package mobi.richaze.llbag.infrastructure.hibernate;

import java.io.Serializable;
import java.util.List;

import org.hibernate.LockOptions;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

/**
 * 此功能为所有领域对象提供数据仓储处理, 此接口实现本系统实体的CRUD操作
 */
@Repository("HibernateRepository")
@SuppressWarnings("unchecked")
public class HibernateRepository extends HibernateDaoSupport {
	// private Class<T> entityClass;
	private static final Logger log = LoggerFactory
			.getLogger(HibernateRepository.class);

	public HibernateRepository() {
		// entityClass = (Class<T>) ((ParameterizedType) getClass()
		// .getGenericSuperclass()).getActualTypeArguments()[0];
	}

	@Autowired
	public void setSessionFactorys(SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}

	public <T> T getEntity(Class<T> entityClass, Serializable id) {
		log.debug("getting Entity instance with id: " + id);

		/**
		 * 由于hibernate采用了lazy=true,这样当你用hibernate查询时,返回实际为利用cglib增强的代理类,
		 * 但其并没有实际填充;当你在前端,利用它来取值(getXXX)时,这时Hibernate才会到数据库执行查询,并填充对象,
		 * 但此时如果和这个代理类相关的session已关闭掉,就会产生种错误. 在做一对多时， 有时会出现"could not initialize
		 * proxy, 这个好像是hibernate的缓存问题.问题解决:需要在<class name="" >里设置lazy=" false".
		 * 默认为true
		 */
		// T entity = getHibernateTemplate().load(entityClass, id);
		T entity = getHibernateTemplate().get(entityClass, id);
		return entity;
	}

	public <T> List<T> findByExample(String entityName, T entity) {
		log.debug("通过Example方式查找实体对象");
		try {
			List<T> results = getSession().createCriteria(entityName).add(
					Example.create(entity)).list();
			log.debug("find by example successful, result size: "
					+ results.size());
			return results;
		} catch (RuntimeException re) {
			log.error("find by example failed", re);
			throw re;
		}
	}

	public <T> List<T> findByProperty(String propertyName, Object value) {
		log.debug("finding Account instance with property: " + propertyName
				+ ", value: " + value);
		try {
			String queryString = "from Account as model where model."
					+ propertyName + "= ?";
			Query queryObject = getSession().createQuery(queryString);
			queryObject.setParameter(0, value);
			return queryObject.list();
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw re;
		}
	}

	public <T> Serializable saveEntity(T entity) {
		log.debug("saving Entity instance");
		Serializable id = null;
		try {
			id = getHibernateTemplate().save(entity);
			log.debug("save successful");
		} catch (RuntimeException re) {
			log.error("save failed", re);
			throw re;
		}
		return id;
	}

	public <T> T merge(T entity) {
		log.debug("merging Account instance");
		try {
			T result = (T) getSession().merge(entity);
			log.debug("merge successful");
			return result;
		} catch (RuntimeException re) {
			log.error("merge failed", re);
			throw re;
		}
	}

	/**
	 * 如果对象未保存（Transient状态），调用save方法保存。如果对象已保存（Detached状态），
	 * 调用update方法将对象与Session重新关联
	 * 
	 * @param entity
	 */
	public <T> void attachDirty(T entity) {
		log.debug("attaching dirty Account instance");
		try {
			getSession().saveOrUpdate(entity);
			log.debug("attach successful");
		} catch (RuntimeException re) {
			log.error("attach failed", re);
			throw re;
		}
	}

	/**
	 * 
	 * 将传入的对象状态设置为Transient状态。
	 * 
	 * @param entity
	 */
	public <T> void attachClean(T entity) {
		log.debug("attaching clean Account instance");
		try {
			// 此方法已经过时，由下面方法代替
			// getSession().lock(entity, LockMode.NONE);
			getSession().buildLockRequest(LockOptions.NONE).lock(entity);
			log.debug("attach successful");
		} catch (RuntimeException re) {
			log.error("attach failed", re);
			throw re;
		}
	}

	public <T> void removeEntity(Class<T> entityClass, Serializable id) {
		log.debug("deleting Entity instance");
		T entity = getHibernateTemplate().get(entityClass, id);
		if (entity != null) {
			try {
				getHibernateTemplate().delete(entity);
				log.debug("delete successful");
			} catch (RuntimeException re) {
				log.error("delete failed", re);
				throw re;
			}
		}
	}

	public <T> void updateEntity(T entity) {
		log.debug("updating Entity instance");
		try {
			getHibernateTemplate().update(entity);
			log.debug("updating successful");
		} catch (RuntimeException re) {
			log.error("update failed", re);
			throw re;
		}
	}

	public <T> List<T> getAllEntity() {
		return null;
	}
}
